import 'package:flutter/material.dart';
import 'package:visibility_detector/visibility_detector.dart';

/// Base StatefulWidget
abstract class BasePage extends StatefulWidget {
  final bool isPage;
  const BasePage({Key? key, this.isPage = true}) : super(key: key);
}

/// Loading view
/// empty data
/// error view
abstract class BasePageState<T extends BasePage> extends State<T>
    with
        ScaffoldMixin,
        AppBarStateMixin,
        BottomNavigationBarMixin,
        FloatingActionButtonMixin,
        LoadingView,
        AutomaticKeepAliveClientMixin,
        InitStatusMixin,
        LifecycleMixin {
  late BuildContext _context;
  late ViewStatus viewStatus;

  @override
  void initState() {
    super.initState();
    viewStatus = buildInitStatus();
    WidgetsBinding.instance.endOfFrame.then((value) {
      if (mounted) {
        debugPrint("layoutInitComplete。");
        layoutInitComplete(context);
      }
    });
  }

  @override
  Widget build(BuildContext context) {
    super.build(context);
    _context = context;
    var canPop = ModalRoute.of(context)?.canPop ?? false;
    Widget body;
    switch (viewStatus) {
      case ViewStatus.loading:
        body = buildLoading();
        break;
      case ViewStatus.normal:
        body = buildBody(context);
        break;
      case ViewStatus.error:
        body = buildError();
        break;
    }
    return WillPopScope(
      onWillPop: _onWillPop,
      child: VisibilityDetector(
        key: Key("$T"),

        /// 当前页面显示时会触发onResume，隐藏时会触发onPause.
        onVisibilityChanged: (VisibilityInfo info) {
          if ("$T" == "${(info.key as ValueKey).value}") {
            if (info.visibleFraction == 1) {
              onResume(context);
            } else {
              onPause(context);
            }
          }
        },
        child: widget.isPage
            ? Scaffold(
                backgroundColor: backgroundColor(),
                appBar: showAppBar()
                    ? AppBar(
                        title: buildTitle(context),
                        centerTitle: centerTitle(context),
                        leading: canPop || customLeftWidget()
                            ? leftWidget(context)
                            : null,
                        leadingWidth: leftWidgetWidth(),
                        actions: rightWidgets(context),
                        bottom: appBarBottom(),
                        flexibleSpace: flexibleSpace(),
                      )
                    : null,
                drawer: buildDrawer(context),
                endDrawer: buildEndDrawer(context),
                body: body,
                floatingActionButton: buildFloatingActionButton(context),
                bottomNavigationBar: buildBottomNavigationBar(context),
              )
            : body,
      ),
    );
  }

  Widget buildBody(BuildContext context);

  Future<bool> _onWillPop() async {
    debugPrint("${runtimeType}: _onWillPop");
    if (await interceptBackPressed(_context)) {
      return false;
    }
    return true;
  }

  Future<bool> pop<O extends Object?>([O? result]) {
    return Navigator.maybePop(context, result);
  }

  Future<O?> push<O extends Object?>(Widget widget) {
    return Navigator.of(context)
        .push(MaterialPageRoute(builder: (ctx) => widget));
  }

  void layoutInitComplete(BuildContext context) {}

  void changeViewStatus(ViewStatus status) {
    setState(() {
      viewStatus = status;
    });
  }

  @override
  bool get wantKeepAlive => true;
}

mixin ScaffoldMixin<T extends StatefulWidget> on State<T> {
  Color? backgroundColor() {
    return null;
  }

  Widget? buildDrawer(BuildContext context) {
    return null;
  }

  Widget? buildEndDrawer(BuildContext context) {
    return null;
  }
}

mixin AppBarStateMixin<T extends StatefulWidget> on State<T> {
  bool showAppBar() {
    return true;
  }

  bool customLeftWidget() {
    return false;
  }

  Widget? leftWidget(BuildContext context) {
    return const BackButton();
  }

  List<Widget>? rightWidgets(BuildContext context) {
    return null;
  }

  Widget? buildTitle(BuildContext context) {
    return const Text("BasePage");
  }

  bool centerTitle(BuildContext context) {
    return true;
  }

  Future<bool> interceptBackPressed(BuildContext context) async {
    return Future.value(false);
  }

  Widget? flexibleSpace() {
    return null;
  }

  PreferredSizeWidget? appBarBottom() {
    return null;
  }

  /// 左邊默認為appbar的高度
  /// Source code:
  /// const double _kLeadingWidth = kToolbarHeight;
  double leftWidgetWidth() {
    return kToolbarHeight;
  }
}

mixin LifecycleMixin<T extends StatefulWidget> on State<T> {
  void onResume(BuildContext context) {}

  void onPause(BuildContext context) {}
}

mixin FloatingActionButtonMixin<T extends StatefulWidget> on State<T> {
  Widget? buildFloatingActionButton(BuildContext context) {
    return null;
  }
}

mixin BottomNavigationBarMixin<T extends StatefulWidget> on State<T> {
  Widget? buildBottomNavigationBar(BuildContext context) {
    return null;
  }
}

enum ViewStatus { loading, normal, error }

mixin LoadingView {
  Widget buildLoading({Widget? loading}) {
    var defaultLoading = const Center(
      child: Text('loading...'),
    );
    return loading ?? defaultLoading;
  }

  Widget buildError({Widget? error}) {
    var defaultError = const Center(
      child: Text('error...'),
    );
    return error ?? defaultError;
  }
}

mixin ErrorView {
  showError({Widget? loading}) {}

  hideError() {}
}

mixin NoAppBarMixin<T extends BasePage> on BasePageState<T> {
  @override
  bool showAppBar() {
    return false;
  }
}

mixin InitStatusMixin<T extends StatefulWidget> on State<T> {
  ViewStatus buildInitStatus() {
    return ViewStatus.loading;
  }
}

mixin InitNormalStatusMixin<T extends StatefulWidget> on State<T> {
  ViewStatus buildInitStatus() {
    return ViewStatus.normal;
  }
}
